module Nodes exposing (..)
import Html exposing (Html, a, button, code, div, h1, li, text, ul, br,input)
import Html.Attributes exposing (href,value,style)
import Html.Events exposing (onInput,onClick)
import Http
import Json.Decode as Decode
import Json.Encode as Encode
import Utils
import Nodes.NodeAdder as Adder
import Nodes.NodeEditer as Editer

type Model =
 Model NodeId (List Node) Log Adder.Model (List Editer.Model)

type Msg 
 = GetListResult (Result Http.Error (Result String (List Node)))
 | None
 | AdderMsg Adder.Msg
 | EditerMsg  Editer.WrapMsg
 | Refresh
 

type Node = Node Id Title IsArticle CreateTime


type alias Log = String
type alias Id = Int
type alias NodeId = Int
type alias Title = String
type alias IsArticle = Int
type alias CreateTime = String

nodeListDecoder : Decode.Decoder (List Node)
nodeListDecoder =
 let 
  nodeDecoder = Decode.map4 Node (Decode.field "id" Decode.int) (Decode.field "title" Decode.string) (Decode.field "isArticle" Decode.int) (Decode.field "create_time" Decode.string)
 in 
  Decode.list nodeDecoder

initModel : Model
initModel = Model -1 [] ""  (Adder.initModel -1) []

refresh : Int -> Model -> (Model,Cmd Msg)
refresh nodeId ((Model oldNodeId nodeList log adder editers) as model) =
 let
  url = "/nodes/" ++ toString nodeId
  errDecoder = Decode.map Err (Decode.field "err" Decode.string)
  okDecoder = Decode.map Ok (Decode.field "ok" nodeListDecoder)
  decoder = Decode.oneOf [errDecoder,okDecoder]
  request = Http.get url decoder
  newAdder = Adder.initModel nodeId
 in
  (Model nodeId nodeList (log ++ " Refreshing... ") newAdder editers, Http.send GetListResult request)


nodeToEditer : Node -> Editer.Model
nodeToEditer (Node id title isArticle cTime) =
 Editer.Model id title "" False


reset : Id -> Model -> Model
reset id (Model _ nodes log adder editers) =
 Model id nodes log adder editers
 

update : Msg -> Model -> (Model,Cmd Msg)
update msg ((Model oldNodeId nodeList log adder editers) as model) =
 case msg of
  GetListResult (Err err) ->
   (Model oldNodeId nodeList (toString err) adder editers,Cmd.none)

  GetListResult (Ok result) ->
   case result of
    Ok newNodeList -> 
     let 
      newEditers = List.map nodeToEditer newNodeList
     in (Model oldNodeId newNodeList (log ++ " GetList Ok. ") adder newEditers,Cmd.none)
    Err err -> (Model oldNodeId nodeList (log ++ " Get list failed: " ++ err) adder editers,Cmd.none)
  
  None -> (model,Cmd.none)

  AdderMsg subMsg -> 
   let
    (newAdder,cmd) = Adder.update subMsg adder
   in (Model oldNodeId nodeList log newAdder editers,Cmd.map AdderMsg cmd)

  EditerMsg subMsg -> 
   let
    tuple = List.map (\editer -> Editer.update subMsg editer) editers
    updatedEditers = List.map Tuple.first tuple
    cmds = List.map Tuple.second tuple
    cmd = (Maybe.withDefault Cmd.none) <| List.head <| List.filter (\c -> c /= Cmd.none) <| cmds
   in (Model oldNodeId nodeList log adder updatedEditers,Cmd.map EditerMsg cmd)
  
  Refresh ->
   refresh oldNodeId model
-- (Model oldNodeId nodeList log adder newEditers,Cmd.none)
  

refreshBtn : Html Msg
refreshBtn =
 div [] [ button [style [("background-color","green"),("color","white")],onClick Refresh] [text "refresh"] ]
 

view : Model -> Html Msg
view (Model oldNodeId nodeList log adder editers) =
 div []
  [ nodeListView nodeList editers
  , br [] []
  , br [] []
  , Html.map AdderMsg (Adder.view adder)
  , br [] []
  , text ("Nodes: " ++ log)
  , br [] []
  , text ("NodeId: " ++ toString oldNodeId)]

nodeToString : Node -> String
nodeToString (Node id title isArticle createTime) = 
 let typeTag =
  case isArticle of
   0 -> "[目录] "
   1 -> "[文章] "
   _ -> "[未知类型] "
 in
  typeTag ++ title

nodeToLink : Node -> Html Msg
nodeToLink ((Node id title isArticle createTime) as node) =
 let 
  href_text =
   case isArticle of
    0 -> "#/nodes/" ++ toString id -- isn't
    1 -> "#/article/" ++ toString id -- is
    _ -> "#" -- unknown
 in a [href href_text] [text (nodeToString node)]


nodeListView : List Node -> List Editer.Model -> Html Msg
nodeListView nodeList editerModels =
 let 
  pairs = List.map2 (,) nodeList editerModels
  divs = List.map (\(node,editer) -> div [] [nodeToLink node,Html.map EditerMsg (Editer.view editer)]) pairs
 in 
  div [] divs